﻿using System;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol;
using HK.Core.Common.Protocol.Data;
using HK.Editor.GUIEx.Protocol.Pagination;
using UnityEngine;

namespace HK.Editor.GUIEx.Pagination
{
	/// <summary>
	/// 分页信息
	/// </summary>
	[Serializable]
	public class Pagination : JsonData<Pagination>, IPagination
	{

#region Create

		/// <summary>
		/// 创建分页信息
		/// </summary>
		/// <param name="iPageSize">分页大小</param>
		/// <returns>分页信息</returns>
		public static Pagination Create(int iPageSize)
		{
			return new Pagination { PageSize = iPageSize };
		}

#endregion
        
		/// <summary>
		/// 保护构造函数
		/// </summary>
		protected Pagination() {}
        
		/// <summary>
		/// 上一次页码索引
		/// </summary>
		public int LastIndex { get; private set; } = 0;
		
		[SerializeField]
		private int index = 0;
		/// <summary>
		/// 页码索引
		/// </summary>
		public int Index
		{
			get => index;
			set
			{
				LastIndex = index;
				index = value;
			}
		}

		[SerializeField]
		private int pageSize = 0;
		/// <summary>
		/// 页数
		/// </summary>
		public int PageSize 
		{
			get => pageSize;
			set => pageSize = value;
		}
        
		/// <summary>
		/// 滚动条显示标志位 - 横轴
		/// </summary>
		public bool HBarVisible { get; set; } = false;

		/// <summary>
		/// 滚动条显示标志位 - 纵轴
		/// </summary>
		public bool VBarVisible { get; set; } = false;

		/// <summary>
		/// 取得当前开始索引
		/// </summary>
		/// <param name="iElementNo">Element No</param>
		/// <returns>当前开始索引</returns>
		public int GetCurVisibleLength(int iElementNo)
		{
			var curMaxNum = (index + 1 ) * PageSize;
			curMaxNum = Math.Max(0, curMaxNum);
			curMaxNum = Math.Min(curMaxNum, iElementNo);
			if (GetVisibleRange(curMaxNum, out var oStart, out var oEnd))
			{
				return oEnd - oStart;
			}
			return iElementNo;
		}

		/// <summary>
		/// 取得可视长度
		/// </summary>
		/// <param name="iElementNo">Element No</param>
		/// <returns>可视长度</returns>
		internal int GetVisibleLength(int iElementNo) 
		{
			if (GetVisibleRange(iElementNo, out var start, out var end)) 
			{
				return end - start;
			}

			return iElementNo;
		}

		/// <summary>
		/// 取得Element所在的分页索引
		/// </summary>
		/// <param name="iElementIndex">Element索引</param>
		/// <returns>Element所在的页码</returns>
		internal int GetPageIndexByElementIndex(int iElementIndex) 
		{
			return Mathf.FloorToInt(iElementIndex / (float)PageSize);
		}

		/// <summary>
		/// 取得总页数
		/// </summary>
		/// <param name="iCount">Element总数</param>
		/// <returns>总页数</returns>
		public int GetPageCount(int iCount)
		{
			var maxPageIndex = CalcPageIndex(iCount, out var oMode);
			if (0 != oMode)
			{
				maxPageIndex += 1;
			}
			return maxPageIndex;
		}

		/// <summary>
		/// 校验是否可分页
		/// </summary>
		/// <param name="iElementNo">Element No</param>
		/// <returns>true:可分页; false:不可分页;</returns>
		public bool IsPageable(int iElementNo)
		{
			return iElementNo > PageSize;
		}

		/// <summary>
		/// 重置索引
		/// </summary>
		public void ResetIndex()
		{
			LastIndex = 0;
			index = 0;
		}

		/// <summary>
		/// 计算页索引
		/// </summary>
		/// <param name="iCount">Element总数</param>
		/// <param name="oMode">余数</param>
		/// <returns>页索引</returns>
		private int CalcPageIndex(int iCount, out int oMode)
		{
			oMode = iCount % PageSize;
			return (iCount - oMode) / PageSize;
		}
        
		/// <summary>
		/// 取得当前分页可视范围
		/// </summary>
		/// <param name="iElementNo">Element No</param>
		/// <param name="oStartIndex">开始索引(从0开始)</param>
		/// <param name="oEndIndex">结束索引</param>
		/// <returns>true:可分页; false:不可分页;</returns>
		public bool GetVisibleRange(int iElementNo, out int oStartIndex, out int oEndIndex) 
		{
			if (0 >= iElementNo)
			{
				oStartIndex = 0;
				oEndIndex = 0;
				return false;
			}

			if (!IsPageable(iElementNo))
			{
				oStartIndex = 0;
				oEndIndex = iElementNo;
				return true;
			}
            
			var size = PageSize;
			oStartIndex = Mathf.Clamp(index * size, 0, iElementNo - 1);
			oEndIndex = Mathf.Min(oStartIndex + size, iElementNo);
			return true;
		}

		/// <summary>
		/// 校验是否可以移动分页
		/// </summary>
		/// <returns>true:可; false:不可;</returns>
		public bool IsMovePageEnable()
		{
			return false;
		}

		/// <summary>
		/// 校验是否可以移动到上一页
		/// </summary>
		/// <returns>true:可; false:不可;</returns>
		public bool IsMovePrevPageEnable()
		{
			return 0 < index;
		}

		/// <summary>
		/// 校验是否可以移动到下一页
		/// </summary>
		/// <param name="iCount">数量</param>
		/// <returns>true:可; false:不可;</returns>
		public bool IsMoveNextPageEnable(int iCount)
		{
			if (0 >= iCount) return false;
			var maxPageIndex = CalcPageIndex(iCount, out var oMode);
			return index < maxPageIndex;
		}

		/// <summary>
		/// 应用数据
		/// </summary>
		/// <param name="iData">数据</param>
		/// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
		/// <returns>true:有变更; false:无变更;</returns>
		public override bool ApplyData(IJsonData iData, bool iImport = false)
		{
			Dirty = false;
			if (null == iData || !iData.Valid) return false;
			var dirty = base.ApplyData(iData, iImport);
			if (dirty && !iImport)
			{
				Dirty = true;
			}

			// 重置标脏标志位
			if (iData is IPagination pagination)
			{
				index = UpdateValue(index, pagination.Index, iImport);
				LastIndex = pagination.LastIndex;

				pageSize = UpdateValue(pageSize, pagination.PageSize, iImport);
				HBarVisible = pagination.HBarVisible;
				VBarVisible = pagination.VBarVisible;
			}

			return Dirty;
		}
        
		/// <summary>
		/// 清空
		/// </summary>
		public override void Clear()
		{
			base.Clear();
			index = 0;
			LastIndex = 0;

			pageSize = 0;
			HBarVisible = false;
			HBarVisible = false;
		}
	}
}
    
